package com.repair.order.service.impl;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.repair.api.category.request.ServiceQeuryByIdRequest;
import com.repair.api.category.response.ServiceQueryNameResponse;
import com.repair.api.category.service.CategoryFacadeService;
import com.repair.api.comment.request.OrderCommRequest;
import com.repair.api.comment.response.CommentOrderResponse;
import com.repair.api.order.constant.OrderStatus;
import com.repair.api.order.request.OrderAddGrabPoolRequest;
import com.repair.api.order.request.OrderAssignRequest;
import com.repair.api.order.request.OrderQueryPageRequest;
import com.repair.api.order.request.OrderQueryRequest;
import com.repair.api.order.request.condition.OrderCondition;
import com.repair.api.order.request.condition.OrderNumQueryCondition;
import com.repair.api.order.request.param.OrderAssignParam;
import com.repair.api.order.request.param.OrderCommentParam;
import com.repair.api.order.request.param.OrderPayParam;
import com.repair.api.order.request.param.OrderQueryParam;
import com.repair.api.order.response.OrderAddGrabPoolResponse;
import com.repair.api.order.response.OrderAssignResponse;
import com.repair.api.order.response.OrderQueryResponse;
import com.repair.api.order.response.vo.OrderVO;
import com.repair.api.pay.request.PayRefundRequest;
import com.repair.api.pay.request.PaymentAddRequest;
import com.repair.api.pay.request.param.PaymentAddParam;
import com.repair.api.pay.response.PayAddResponse;
import com.repair.api.pay.response.PayRefundResponse;
import com.repair.api.pay.response.vo.PaymentInfoVO;
import com.repair.api.pay.service.PaymentFacadeService;
import com.repair.api.user.request.UserQueryRequest;
import com.repair.api.user.response.UserQueryResponse;
import com.repair.api.user.response.data.UserInfo;
import com.repair.api.user.service.UserFacadeService;
import com.repair.api.worker.request.WorkerQueryRequest;
import com.repair.api.worker.response.WorkerQueryResponse;
import com.repair.api.worker.response.data.WorkerInfo;
import com.repair.api.worker.service.WorkerFacadeService;
import com.repair.base.exception.BizErrorCode;
import com.repair.base.exception.BizException;
import com.repair.base.exception.SystemErrorCode;
import com.repair.base.exception.SystemException;
import com.repair.base.response.PageResponse;
import com.repair.base.utils.ResponseCode;
import com.repair.lock.annotaion.DistributeLock;
import com.repair.order.exception.OrderException;
import com.repair.order.mapper.OrderMapper;
import com.repair.order.pojo.convertor.OrderConvertor;
import com.repair.order.pojo.dto.OrderCreateParam;
import com.repair.order.pojo.entity.Order;
import com.repair.order.pojo.entity.OrderStream;
import com.repair.order.service.OrderService;
import com.repair.order.service.OrderStreamService;
import com.repair.order.utils.WorkerId;
import com.repair.order.validator.OrderCreateValidator;
import com.repair.satoken.utils.StpKit;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.repair.api.order.constant.OrderStatus.*;
import static com.repair.pay.config.AliPayConfig.*;

/**
 * <p>
 * 订单 服务实现类
 * </p>
 *
 * @author chunyu
 * @since 2024-09-29
 */
@Slf4j
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {


    private static final String GATEWAY_URL = "https://openapi-sandbox.dl.alipaydev.com/gateway.do";
    private static final String FORMAT = "JSON";
    private static final String CHARSET = "UTF-8";
    //签名方式
    private static final String SIGN_TYPE = "RSA2";

    @Autowired
    private OrderCreateValidator orderCreateValidator;
    @Autowired
    private CategoryFacadeService categoryFacadeService;

    @Autowired
    private OrderStreamService orderStreamService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @DubboReference
    private WorkerFacadeService workerFacadeService;
    @Autowired
    @Lazy
    private OrderServiceImpl orderServiceimpl;

    @DubboReference
    private PaymentFacadeService paymentFacadeService;

    @DubboReference
    private UserFacadeService userFacadeService;

    // 这里需要加分布式锁
    @DistributeLock(scene = "createOrder", keyExpression = "#identifier", expireTime = 5000)
    @Override
    public void createOrder(OrderCreateParam orderCreateParam, String identifier) {
        Long userId = Long.valueOf((String) StpKit.USER.getLoginId());

        if (StringUtils.hasText(orderCreateParam.getOrderNum())) {
            // 修改
            updateOrder(orderCreateParam, userId);
        } else {
            // 新增
            createOrder(orderCreateParam, identifier, userId);
        }


    }

    private void updateOrder(OrderCreateParam orderCreateParam, Long userId) {

        Order order = OrderConvertor.INSTANCE.mapToEntity(orderCreateParam);

        // 更新订单状态
        UpdateWrapper<Order> wrapper = new UpdateWrapper<Order>()
                .eq("order_num", orderCreateParam.getOrderNum())
                .eq("user_id", userId);
        int i = baseMapper.update(order, wrapper);
        Assert.isTrue(i == 1, () -> new BizException(ResponseCode.UPDATE_FAILED));
    }

    private void createOrder(OrderCreateParam orderCreateParam, String identifier, Long userId) {
        // 校验订单参数
        try {
            orderCreateValidator.validate(orderCreateParam);
        } catch (OrderException e) {
            throw new RuntimeException(e);
        }
        // 幂等（这有个问题 就是这里没有状态，所以只能想其他办法）
        // 用户每次下单前都会请求服务端  获取一个token随机串
        // 用这个当作一个标识可以解决重复下单问题，而且可以当作幂等号唯一校验
        if (this.getOne(new QueryWrapper<Order>().eq("identifier", identifier)) != null) {
            throw new BizException(ResponseCode.DUPLICATED);
        }
        log.debug("identifier: " + identifier);

        // 生成唯一订单号
        String orderNum = generateOrderNum();

        // 调用服务分类 查询服务名称
        String serviceName = getServiceName(orderCreateParam);

        // 创建订单
        // 解决长事务问题 这里不能用this调用 this走普通对象 不走代理对象事务会失效
        Order order = new Order(orderCreateParam, orderNum, userId, identifier);
        order.setServiceCategoryName(serviceName);
        UserQueryRequest request = new UserQueryRequest(userId);
        UserQueryResponse<UserInfo> response = userFacadeService.query(request);
        if (!response.getSuccess()) {
            throw new BizException(BizErrorCode.REMOTE_CALL_RESPONSE_IS_FAILED);
        }
        UserInfo userInfo = response.getData();
        order.setUserTelephone(userInfo.getTelephone());
        order.setUserNickName(userInfo.getNickName());

        orderServiceimpl.createOrderAndStream(order);
        // 新建订单应该直接进抢单池 （异步）
        orderServiceimpl.addOrderToGrabPool(order.getOrderNum());

        // TODO 如果没人抢 redis就没了 应该通知重新入池或者派单
        // TODO 后面考虑怎么和redis配置使用
        // 使用hash 存储订单id
        //String key = GRAB_ORDER_POOL;
        //String listKey = GRAB_ORDER_POOL_ORDER_LISTS;
        //Map<String, Object> orderMap = new HashMap<>();
        //// 将订单信息放入map
        //convertor(orderMap, order);
        //stringRedisTemplate.opsForHash().putAll(key, orderMap);
        // TODO 加了个 抢单池订单列表集合  暂时没想明白


        //stringRedisTemplate.opsForSet().add(listKey, orderNum);
        // 这如果加过期时间 就需要在订单过期时修改订单状态
        //stringRedisTemplate.expire(key, 1, TimeUnit.HOURS);
    }

    private String getServiceName(OrderCreateParam orderCreateParam) {
        ServiceQeuryByIdRequest request = new ServiceQeuryByIdRequest();
        request.setId(orderCreateParam.getServiceCategoryId());
        ServiceQueryNameResponse response = categoryFacadeService.getServiceNameById(request);
        if (!response.getSuccess()) {
            throw new BizException(BizErrorCode.REMOTE_CALL_RESPONSE_IS_FAILED);
        }
        String serviceName = response.getServiceName();
        return serviceName;
    }

    @Transactional(rollbackFor = Exception.class)
    public void createOrderAndStream(Order order) {
        boolean result = this.save(order);
        Assert.isTrue(result, () -> new BizException(ResponseCode.INSERT_FAILED));
        // 创建订单流水
        OrderStream orderStream = new OrderStream(order);
        result = orderStreamService.save(orderStream);
        Assert.isTrue(result, () -> new BizException(ResponseCode.INSERT_FAILED));
    }

    @Override
    public PageResponse<OrderVO> getOrders(String status, int pageSize, int currentPage) {
        Long userId = Long.valueOf((String) StpKit.USER.getLoginId());
        IPage<Order> page = new Page<>();
        page.setSize(pageSize);
        page.setCurrent(currentPage);
        QueryWrapper<Order> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId)
                .orderByDesc("update_time");
        List<Order> orderList;
        switch (status) {
            case "ALL":
                break;
            case "10":
                wrapper.in("status", PENDING.name(), ASSIGNED.name(), REJECTED.name(), WAITING_FOR_BID.name());
                break;
            case "20":
                wrapper.in("status", BID_ACCEPTED.name(), ACCEPTED.name());
                break;
            case "30":
                wrapper.eq("status", IN_SERVICE.name());
                break;
            case "40":
                wrapper.eq("status", AWAITING_PAYMENT.name());
                break;
            case "50":
                wrapper.eq("status", COMPLETED.name());
                break;
            case "60":
                wrapper.eq("status", CANCELED.name());
                break;
            case "70":
                wrapper.eq("status", RATED.name());
                break;
            default:
                throw new BizException(ResponseCode.ILLEGAL_ARGUMENT);
        }
        IPage<Order> orderPage = baseMapper.selectPage(page, wrapper);
        orderList = orderPage.getRecords();

        PageResponse<OrderVO> response = new PageResponse<>();
        response.setPageSize((int) orderPage.getSize());
        response.setTotal((int) orderPage.getTotal());
        response.setCurrentPage((int) orderPage.getCurrent());
        response.setPageTotal((int) orderPage.getPages());
        // 使用mapstruct --（entity->vo）
        List<OrderVO> orderVOList = OrderConvertor.INSTANCE.mapToVOList(orderList);
        response.setData(orderVOList);
        return response;


    }

    @Override
    public PageResponse<OrderVO> getOrdersByWorker(String status, int pageSize, int currentPage) {
        Long workerId = Long.valueOf((String) StpKit.WORKER.getLoginId());
        // TODO 先redis查， 查不到去mysql


        // mysql兜底
        IPage<Order> page = new Page<>();
        page.setSize(pageSize);
        page.setCurrent(currentPage);
        QueryWrapper<Order> wrapper = new QueryWrapper<>();
        wrapper.eq("worker_id", workerId)
                .orderByDesc("update_time");
        switch (status) {
            case "ALL":
                break;
            case "10":
                wrapper.in("status", ACCEPTED.name());
                break;
            case "20":
                wrapper.in("status", BID_ACCEPTED.name());
                break;
            case "30":
                wrapper.in("status", REJECTED.name());
                break;
            case "40":
                wrapper.eq("status", COMPLETED.name());
                break;
            case "50":
                wrapper.eq("status", CANCELED.name());
                break;
            default:
                throw new BizException(ResponseCode.ILLEGAL_ARGUMENT);
        }
        IPage<Order> orderPage = baseMapper.selectPage(page, wrapper);
        List<Order> records = orderPage.getRecords();

        PageResponse<OrderVO> response = new PageResponse<>();
        response.setTotal((int) orderPage.getTotal());
        response.setCurrentPage(currentPage);
        response.setPageTotal((int) orderPage.getPages());
        List<OrderVO> orderVOList = OrderConvertor.INSTANCE.mapToVOList(records);
        response.setData(orderVOList);
        return response;
    }

    @Override
    public OrderVO getOrderInfoByUser(Long orderNum) {

        Long userId = Long.valueOf((String) StpKit.USER.getLoginId());
        Order order = getOne(new QueryWrapper<Order>().eq("order_num", orderNum).eq("user_id", userId));
        return OrderConvertor.INSTANCE.mapToVO(order);
    }

    @Override
    public OrderVO getOrderInfoByWorker(Long orderNum) {

        Long workId = Long.valueOf((String) StpKit.WORKER.getLoginId());
        Order order = getOne(new QueryWrapper<Order>().eq("order_num", orderNum));
        return OrderConvertor.INSTANCE.mapToVO(order);
    }

    @Override
    public PageResponse<OrderVO> getGrabPools(int pageSize, int currentPage) {

        IPage<Order> page = new Page<>();
        page.setSize(pageSize);
        page.setCurrent(currentPage);
        QueryWrapper<Order> wrapper = new QueryWrapper<>();
        wrapper.orderByDesc("update_time")
                .eq("status", WAITING_FOR_BID.name());
        IPage<Order> orderPage = baseMapper.selectPage(page, wrapper);
        List<Order> records = orderPage.getRecords();
        PageResponse<OrderVO> response = new PageResponse<>();
        response.setTotal((int) orderPage.getTotal());
        response.setCurrentPage(currentPage);
        response.setPageTotal((int) orderPage.getPages());
        List<OrderVO> orderVOList = OrderConvertor.INSTANCE.mapToVOList(records);
        response.setData(orderVOList);
        return response;
    }

    @DistributeLock(scene = "workerGrabOrder", keyExpression = "#orderNum")
    @Override
    public void workerGrabOrder(Long orderNum) {
        Long workerId = Long.valueOf((String) StpKit.WORKER.getLoginId());
        Order order = getOne(new QueryWrapper<Order>().eq("order_num", orderNum));

        // 校验订单状态是否为 "WAITING_FOR_BID"
        Assert.isTrue(order.getStatus().equals(WAITING_FOR_BID.name()),
                () -> new BizException(ResponseCode.ILLEGAL_ARGUMENT));
        // 设置师傅的ID
        order.setWorkerId(workerId);
        WorkerQueryResponse<WorkerInfo> worker = workerFacadeService.query(new WorkerQueryRequest(workerId));
        Assert.notNull(worker, () -> new BizException(ResponseCode.WORKER_NOT_FOUND));
        // 设置师傅的昵称和联系方式
        order.setWorkerNickName(worker.getData().getNickname());
        order.setWorkerPhone(worker.getData().getPhone());
        // 更新订单状态为 "BID_ACCEPTED"
        // TODO 获取师傅信息  接单数+1

        order.setStatus(BID_ACCEPTED.name());
        order.setTakeTime(LocalDateTime.now());
        orderServiceimpl.grabOrder(order, orderNum);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void submitWorkBefore(Long orderNum, String workBeforePhotoUrl) {

        Long workId = Long.valueOf((String) StpKit.WORKER.getLoginId());
        Order order = baseMapper.selectOne(new QueryWrapper<Order>().eq("order_num", orderNum).eq("worker_id", workId));
        Assert.isTrue(order.getStatus().equals(BID_ACCEPTED.name()) || order.getStatus().equals(ACCEPTED.name()), () -> new BizException(ResponseCode.ILLEGAL_ARGUMENT));
        UpdateWrapper<Order> wrapper = new UpdateWrapper<>();
        order.setWorkPreTime(LocalDateTime.now());
        order.setWorkPrePhotoUrl(workBeforePhotoUrl);
        order.setStatus(IN_SERVICE.name());
        order.setServiceTime(LocalDateTime.now());
        wrapper.eq("order_num", orderNum)
                .eq("worker_id", workId);

        baseMapper.update(order, wrapper);
        orderStreamService.save(new OrderStream(order));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void submitWorkAfter(Long orderNum, String workAfterPhotoUrl, String orderPrice) {

        Long workId = Long.valueOf((String) StpKit.WORKER.getLoginId());
        UpdateWrapper<Order> wrapper = new UpdateWrapper<>();
        Order order = baseMapper.selectOne(new QueryWrapper<Order>().eq("order_num", orderNum));
        Assert.isTrue(order.getStatus().equals(IN_SERVICE.name()), () -> new BizException(ResponseCode.ILLEGAL_ARGUMENT));
        order.setWorkAfterTime(LocalDateTime.now());
        order.setWorkAfterPhotoUrl(workAfterPhotoUrl);
        order.setStatus(AWAITING_PAYMENT.name());
        if (orderPrice == null) {
            throw new BizException(ResponseCode.ILLEGAL_ARGUMENT);
        }
        order.setOrderPrice(new BigDecimal(orderPrice));
        wrapper.eq("order_num", orderNum)
                .eq("worker_id", workId);

        baseMapper.update(order, wrapper);
        orderStreamService.save(new OrderStream(order));
    }

    @Override
    public String payOrder(OrderPayParam param, HttpServletResponse httpResponse) {
        executeAliPay(param, httpResponse);
        return "success";
    }

    private void executeAliPay(OrderPayParam param, HttpServletResponse httpResponse) {
        AlipayClient alipayClient = new DefaultAlipayClient(GATEWAY_URL, APP_ID,
                APP_PRIVATE_KEY, FORMAT, CHARSET, ALIPAY_PUBLIC_KEY, SIGN_TYPE);

        // 2. 创建 Request并设置Request参数
        // 发送请求的 Request类
        AlipayTradePagePayRequest request = getAlipayTradePagePayRequest(param);
        // 执行请求，拿到响应的结果，返回给浏览器
        String form = "";
        try {
            // 调用SDK生成表单
            form = alipayClient.pageExecute(request).getBody();
            // 写入文件
            //String filePath = "E:\\Study\\repair-yixiu\\repair-service\\repair-order\\src\\main\\resources\\static\\pay.html"; // 根据你的项目结构调整路径
            String filePath = "/usr/share/nginx/html/web/pay.html";
            Path path = Paths.get(filePath);
            try {
                // 检查文件的父目录是否存在，不存在则创建
                if (Files.notExists(path.getParent())) {
                    Files.createDirectories(path.getParent());
                }
            } catch (IOException e) {
                throw new SystemException(SystemErrorCode.WRITE_FILE_FAILED);
            }
            // 将表单内容写入文件
            Files.write(Paths.get(filePath), form.getBytes(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException | AlipayApiException e) {
            throw new RuntimeException(e);
        }
    }

    private AlipayTradePagePayRequest getAlipayTradePagePayRequest(OrderPayParam param) {
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        request.setNotifyUrl(NOTIFY_URL);
        JSONObject bizContent = new JSONObject();
        // 我们自己的订单号
        bizContent.set("out_trade_no", param.getOrderNum());
        // 通过订单号查询订单
        Order order = baseMapper.selectOne(new QueryWrapper<Order>().eq("order_num", param.getOrderNum()));
        // fixme 暂时关闭 方便测试
        if (!OrderStatus.AWAITING_PAYMENT.name().equals(order.getStatus())) {
            throw new BizException(ResponseCode.ILLEGAL_ARGUMENT);
        }
        // 订单的总金额
        bizContent.set("total_amount", order.getOrderPrice());
        // 支付的名称
        bizContent.set("subject", param.getSubject());
        // 固定配置
        bizContent.set("product_code", "FAST_INSTANT_TRADE_PAY");
        request.setBizContent(bizContent.toString());
        return request;
    }

    @Override
    public void notice(HttpServletRequest request) throws AlipayApiException {


        if ("TRADE_SUCCESS".equals(request.getParameter("trade_status"))) {
            System.out.println("=========支付宝异步回调========");

            Map<String, String> params = new HashMap<>();
            Map<String, String[]> requestParams = request.getParameterMap();
            for (String name : requestParams.keySet()) {
                params.put(name, request.getParameter(name));
                // System.out.println(name + " = " + request.getParameter(name));
            }

            String orderNum = params.get("out_trade_no");
            String orderPrice = params.get("total_amount");
            String gmtPayment = params.get("gmt_payment");
            String alipayTradeNo = params.get("trade_no");
            String buyerPayAmount = params.get("buyer_pay_amount");

            // 买家支付宝账号
            String buyerId = params.get("buyer_id");

            String sign = params.get("sign");
            String content = AlipaySignature.getSignCheckContentV1(params);
            // 验证签名
            boolean checkSignature = AlipaySignature.rsa256CheckContent(content, sign, ALIPAY_PUBLIC_KEY, "UTF-8");
            // 支付宝验签
            if (checkSignature) {
                // 验签通过
                log.debug("交易名称: " + params.get("subject"));
                log.debug("交易状态: " + params.get("trade_status"));
                log.debug("支付宝交易凭证号: " + params.get("trade_no"));
                log.debug("商户订单号: " + params.get("out_trade_no"));
                log.debug("交易金额: " + params.get("total_amount"));
                log.debug("买家在支付宝唯一id: " + params.get("buyer_id"));
                log.debug("买家付款时间: " + params.get("gmt_payment"));
                log.debug("买家付款金额: " + params.get("buyer_pay_amount"));
            }

            // 1. 修改订单状态为 COMPLETED
            UpdateWrapper<Order> wrapper = new UpdateWrapper<>();
            wrapper.eq("order_num", orderNum)
                    .set("status", COMPLETED.name())
                    .set("pay_success_time", gmtPayment)
                    .set("order_price", new BigDecimal(orderPrice))
                    .set("pay_id", alipayTradeNo);
            orderServiceimpl.updateOrderStatusToCompleted(wrapper, orderNum);

            Order order = baseMapper.selectOne(new QueryWrapper<Order>().eq("order_num", orderNum));
            // 2. 设置支付时间 支付价格 TODO 后面可能改异步
            // buyerPayAmount转成BigDecimal
            BigDecimal price = new BigDecimal(buyerPayAmount);
            PaymentAddRequest<PaymentAddParam> payRequest = new PaymentAddRequest<>();
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            LocalDateTime dateTime = LocalDateTime.parse(gmtPayment, formatter);
            payRequest.setData(new PaymentAddParam(alipayTradeNo, "支付宝", buyerId, orderNum, order.getUserId(), price, dateTime));
            PayAddResponse<PaymentInfoVO> response = paymentFacadeService.addPayment(payRequest);
            Assert.isTrue(response.getSuccess(), () -> new BizException(BizErrorCode.REMOTE_CALL_RESPONSE_IS_FAILED));
            // TODO 师傅增加接单数 received_order_sum 加日志
            // TODO 用户增加总金额 total_order_sum 和 order_sum 加日志
            //  用户level计算


        }
    }

    @Override
    public void commentOrder(OrderCommentParam param) {
        // 1.修改订单状态为完成 + 流水
        Long userId = Long.valueOf((String) StpKit.USER.getLoginId());
        orderServiceimpl.updateOrderStatusToRATED(
                new UpdateWrapper<Order>()
                        .eq("order_num", param.getOrderNum())
                        .eq("user_id", userId)
                        .set("status", RATED.name())
                , param.getOrderNum()
        );
        // 2.远程调用 TODO 插入评论记录

        // 3.师傅分数

    }

    @Override
    public void cancelOrder(String orderNum) {
        Long userId = Long.valueOf((String) StpKit.USER.getLoginId());
        Order order = baseMapper.selectOne(new QueryWrapper<Order>().eq("order_num", orderNum));
        // 2.如果订单已支付需要退钱 + 支付表
        if (COMPLETED.name().equals(order.getStatus()) || RATED.name().equals(order.getStatus())) {
            // 退款
            PayRefundRequest payRefundRequest = new PayRefundRequest(orderNum, order.getPayId(), order.getOrderPrice());
            PayRefundResponse<Boolean> refund = paymentFacadeService.refund(payRefundRequest);
            // 可能重复
            if (!refund.getSuccess()) {
                throw new BizException(BizErrorCode.REMOTE_CALL_RESPONSE_IS_FAILED);
            }
            // 3.TODO 用户总成交金额减少 重新计算等级
            // 4.TODO 师傅订单待接单数量减一
        }
        // 1.订单状态改为取消 + 流水
        orderServiceimpl.updateOrderStatusToCancel(orderNum, userId);
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateOrderStatusToCancel(String orderNum, Long userId) {
        int update = baseMapper.update(new UpdateWrapper<Order>()
                .eq("order_num", orderNum)
                .eq("user_id", userId)
                .set("status", CANCELED.name())
        );
        Assert.isTrue(update == 1, () -> new BizException(ResponseCode.UPDATE_FAILED));
        Order order1 = baseMapper.selectOne(new QueryWrapper<Order>().eq("order_num", orderNum).eq("user_id", userId));
        OrderStream orderStream = new OrderStream(order1);
        boolean save = orderStreamService.save(orderStream);
        Assert.isTrue(save, () -> new BizException(ResponseCode.INSERT_FAILED));
    }


    @Override
    public CommentOrderResponse<String> updateCommentId(OrderCommRequest orderCommRequest) {
        // 提取请求中的评论ID
        Long commentId = orderCommRequest.getCommentId();
        // 验证评论ID是否存在，如果不存在，则抛出业务异常
        if (commentId == null) {
            // 抛出业务异常，指示非法参数错误
            throw new BizException(ResponseCode.ILLEGAL_ARGUMENT);
        }
        // 1.修改订单状态为 RATED
        // 提取请求中的订单编号
        String orderNum = orderCommRequest.getOrderNum();
        // 创建更新条件构造器
        UpdateWrapper<Order> wrapper = new UpdateWrapper<>();
        // 设置更新条件和新值 （这里有状态 可以解决幂等）
        wrapper.eq("order_num", orderNum)
                .eq("status", COMPLETED.name())
                .set("comment_id", commentId)
                .set("completion_time", LocalDateTime.now())
                .set("question_description", orderCommRequest.getQuestionDescription())
                .set("status", RATED.name());
        // 调用服务方法执行订单状态更新操作
        orderServiceimpl.updateOrderStatusToRated(wrapper, orderNum);
        // 创建响应对象并设置成功标志
        CommentOrderResponse<String> response = new CommentOrderResponse<>();
        response.setSuccess(true);
        // 返回响应对象
        return response;
    }

    @Override
    public PageResponse<OrderVO> getAllOrders(OrderQueryPageRequest<OrderQueryParam> request) {
        OrderQueryParam param = request.getData();
        Page<Order> page = new Page<>();
        page.setCurrent(request.getCurrentPage());
        page.setSize(request.getPageSize());
        QueryWrapper<Order> wrapper = new QueryWrapper<>();
        wrapper.orderByDesc("update_time");
        if (param != null) {
            wrapper.eq(StringUtils.hasText(param.getStatus()), "status", param.getStatus())
                    .like(StringUtils.hasText(param.getOrderNum()), "order_num", param.getOrderNum())
                    .like(StringUtils.hasText(param.getTelephone()), "user_telephone", param.getTelephone())
                    .eq(param.getServiceCategoryId() != null, "service_category_id", param.getServiceCategoryId())
                    .between(param.getReserveTimeStart() != null && param.getReserveTimeEnd() != null, "reserve_time", param.getReserveTimeStart(), param.getReserveTimeEnd())
                    .eq(param.getUserId() != null, "user_id", param.getUserId())
                    .eq(param.getWorkerId() != null, "worker_id", param.getWorkerId());
        }
        Page<Order> result = baseMapper.selectPage(page, wrapper);
        PageResponse<OrderVO> response = new PageResponse<>();
        response.setData(OrderConvertor.INSTANCE.mapToVOList(result.getRecords()));
        response.setTotal((int) result.getTotal());
        response.setPageSize(request.getPageSize());
        response.setCurrentPage(request.getCurrentPage());
        response.setPageTotal((int) result.getPages());
        response.setSuccess(true);
        return response;
    }

    @Override
    public OrderQueryResponse<OrderVO> getOrderInfoByAdmin(OrderQueryRequest request) {
        OrderCondition condition = request.getCondition();
        Order order = null;
        if (condition instanceof OrderNumQueryCondition) {
            OrderNumQueryCondition orderNumQueryCondition = (OrderNumQueryCondition) condition;
            order = baseMapper.selectOne(new QueryWrapper<Order>().eq("order_num", orderNumQueryCondition.getOrderNum()));
        }
        OrderQueryResponse<OrderVO> response = new OrderQueryResponse<>();
        if (order == null) {
            response.setSuccess(false);
            return response;
        }
        OrderVO orderVO = OrderConvertor.INSTANCE.mapToVO(order);
        response.setData(orderVO);
        response.setSuccess(true);
        return response;
    }

    @Override
    public OrderAssignResponse<Boolean> assignOrderToWorker(OrderAssignRequest<OrderAssignParam> request) {

        OrderAssignParam param = request.getData();
        Long workerId = param.getWorkerId();
        String orderNum = param.getOrderNum();
        if (workerId == null || !StringUtils.hasText(orderNum)) {
            throw new BizException(ResponseCode.ILLEGAL_ARGUMENT);
        }
        orderServiceimpl.updateOrderStatusToAssigned(orderNum, workerId);
        OrderAssignResponse<Boolean> response = new OrderAssignResponse<>();
        response.setSuccess(true);
        response.setData(true);
        return response;
    }

    @Override
    public void acceptOrder(String orderNum) {
        log.debug("师傅确认派单orderNum:{}", orderNum);
        Long workerId = Long.valueOf((String) StpKit.WORKER.getLoginId());
        WorkerQueryResponse<WorkerInfo> worker = workerFacadeService.query(new WorkerQueryRequest(workerId));
        Assert.notNull(worker, () -> new BizException(ResponseCode.WORKER_NOT_FOUND));

        // 2.修改订单状态为 ACCEPTED + 流水
        orderServiceimpl.updateOrderStatusToAccepted(orderNum, workerId, worker.getData());
    }

    @Override
    public void rejectOrder(String orderNum) {

        Long workerId = Long.valueOf((String) StpKit.WORKER.getLoginId());
        orderServiceimpl.updateOrderStatusToRejected(orderNum, workerId);

    }

    @Override
    public OrderAddGrabPoolResponse<Boolean> addOrderToGrabPool(OrderAddGrabPoolRequest request) {
        String orderNum = request.getOrderNum();
        orderServiceimpl.addOrderToGrabPool(orderNum);
        OrderAddGrabPoolResponse<Boolean> response = new OrderAddGrabPoolResponse<>();
        response.setData(true);
        response.setSuccess(true);
        return response;
    }

    //师傅全查派单
    @Override
    public PageResponse<OrderVO> getDispatchPools(int pageSize, int currentPage) {
        Long workerId = Long.valueOf((String) StpKit.WORKER.getLoginId());
        IPage<Order> page = new Page<>();
        page.setSize(pageSize);
        page.setCurrent(currentPage);
        QueryWrapper<Order> wrapper = new QueryWrapper<>();
        wrapper.orderByDesc("update_time")
                .eq("status", ASSIGNED.name())
                .eq("worker_id", workerId);
        IPage<Order> orderPage = baseMapper.selectPage(page, wrapper);
        List<Order> records = orderPage.getRecords();
        PageResponse<OrderVO> response = new PageResponse<>();
        response.setTotal((int) orderPage.getTotal());
        response.setCurrentPage(currentPage);
        response.setPageTotal((int) orderPage.getPages());
        List<OrderVO> orderVOList = OrderConvertor.INSTANCE.mapToVOList(records);
        response.setData(orderVOList);
        return response;
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateOrderStatusToRejected(String orderNum, Long workerId) {

        // 修改订单状态为 REJECTED  并且将订单 worker_id 清空
        UpdateWrapper<Order> wrapper = new UpdateWrapper<Order>()
                .eq("order_num", orderNum)
                .eq("worker_id", workerId)
                .eq("status", ASSIGNED.name())
                .set("status", REJECTED.name())
                .set("worker_id", null);
        int update = baseMapper.update(wrapper);
        Assert.isTrue(update == 1, () -> new BizException(ResponseCode.UPDATE_FAILED));
        Order order = baseMapper.selectOne(new QueryWrapper<Order>().eq("order_num", orderNum));
        // 因为前面清掉表的worker_id 所以这里设置一下
        order.setWorkerId(workerId);
        boolean save = orderStreamService.save(new OrderStream(order));
        Assert.isTrue(save, () -> new BizException(ResponseCode.INSERT_FAILED));
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateOrderStatusToAccepted(String orderNum, Long workerId, WorkerInfo worker) {
        UpdateWrapper<Order> wrapper = new UpdateWrapper<Order>()
                .eq("order_num", orderNum)
                .eq("worker_id", workerId)
                .eq("status", ASSIGNED.name())
                .set("take_time", LocalDateTime.now())
                .set("status", ACCEPTED.name())
                .set("worker_nick_name", worker.getNickname())
                .set("worker_id", workerId)
                .set("worker_phone", worker.getPhone());
        int update = baseMapper.update(wrapper);
        Assert.isTrue(update == 1, () -> new BizException(ResponseCode.UPDATE_FAILED));
        Order order = baseMapper.selectOne(new QueryWrapper<Order>().eq("order_num", orderNum));
        boolean save = orderStreamService.save(new OrderStream(order));
        Assert.isTrue(save, () -> new BizException(ResponseCode.INSERT_FAILED));
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateOrderStatusToAssigned(String orderNum, Long workerId) {
        UpdateWrapper<Order> wrapper = new UpdateWrapper<>();
        // 待抢单和拒接单可以派单
        // 师傅接单后再加师傅信息 (顺带解决幂等)
        wrapper.eq("order_num", orderNum)
                .in("status", WAITING_FOR_BID.name(), REJECTED.name(), PENDING.name())
                .set("worker_id", workerId)
                .set("status", ASSIGNED.name());
        int update = baseMapper.update(wrapper);
        Assert.isTrue(update == 1, () -> new BizException(ResponseCode.UPDATE_FAILED));
        Order order = baseMapper.selectOne(new QueryWrapper<Order>().eq("order_num", orderNum));
        boolean save = orderStreamService.save(new OrderStream(order));
        Assert.isTrue(save, () -> new BizException(ResponseCode.INSERT_FAILED));
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateOrderStatusToRated(UpdateWrapper<Order> wrapper, String orderNum) {
        int update = baseMapper.update(wrapper);
        Assert.isTrue(update == 1, () -> new BizException(ResponseCode.UPDATE_FAILED));
        Order order = baseMapper.selectOne(new QueryWrapper<Order>().eq("order_num", orderNum));
        boolean save = orderStreamService.save(new OrderStream(order));
        Assert.isTrue(save, () -> new BizException(ResponseCode.INSERT_FAILED));
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateOrderStatusToRATED(UpdateWrapper<Order> set, Long orderNum) {
        int i = baseMapper.update(set);
        Assert.isTrue(i == 1, () -> new BizException(ResponseCode.UPDATE_FAILED));
        Order order1 = baseMapper.selectOne(new QueryWrapper<Order>().eq("order_num", orderNum));
        OrderStream orderStream = new OrderStream(order1);
        boolean save = orderStreamService.save(orderStream);
        Assert.isTrue(save, () -> new BizException(ResponseCode.INSERT_FAILED));

    }

    @Transactional(rollbackFor = Exception.class)
    public void updateOrderStatusToCompleted(UpdateWrapper<Order> wrapper, String orderNum) {
        int i = baseMapper.update(wrapper);
        Assert.isTrue(i == 1, () -> new BizException(ResponseCode.UPDATE_FAILED));
        Order order1 = baseMapper.selectOne(new QueryWrapper<Order>().eq("order_num", orderNum));
        OrderStream orderStream = new OrderStream(order1);
        boolean save = orderStreamService.save(orderStream);
        Assert.isTrue(save, () -> new BizException(ResponseCode.INSERT_FAILED));
    }

    @Transactional(rollbackFor = Exception.class)
    public void grabOrder(Order order, Long orderNum) {
        baseMapper.update(order, new QueryWrapper<Order>().eq("order_num", orderNum));
        orderStreamService.save(new OrderStream(order));
    }

    /*使用自定义线程池*/
    @Transactional(rollbackFor = Exception.class)
    //@Async("grabOrderPoolExecutor")
    public void addOrderToGrabPool(String orderNum) {

        Order order = new Order();
        order.setStatus(WAITING_FOR_BID.name());
        // 添加状态条件 解决幂等
        UpdateWrapper<Order> wrapper = new UpdateWrapper<Order>()
                .eq("order_num", orderNum)
                .in("status", PENDING.name(), REJECTED.name());

        boolean result = this.update(order, wrapper);
        Assert.isTrue(result, () -> new BizException(ResponseCode.UPDATE_FAILED));

        order = baseMapper.selectOne(new QueryWrapper<Order>().eq("order_num", orderNum));
        OrderStream orderStream = new OrderStream(order);
        result = orderStreamService.save(orderStream);
        Assert.isTrue(result, () -> new BizException(ResponseCode.INSERT_FAILED));
    }

    private void convertor(Map<String, Object> orderMap, Order order) {
        orderMap.put("identifier", order.getIdentifier());
        orderMap.put("orderNum", order.getOrderNum());
        orderMap.put("orderAddress", order.getOrderAddress());
        orderMap.put("orderPrice", order.getOrderPrice());
        orderMap.put("userId", order.getUserId());
        orderMap.put("userNickName", order.getUserNickName());
        orderMap.put("userTelephone", order.getUserTelephone());
        orderMap.put("workerId", order.getWorkerId());
        orderMap.put("workerNickName", order.getWorkerNickName());
        orderMap.put("workerPhone", order.getWorkerPhone());
        orderMap.put("status", order.getStatus());
        orderMap.put("serviceCategoryName", order.getServiceCategoryName());
        orderMap.put("serviceCategoryId", order.getServiceCategoryId());
        orderMap.put("servicePrice", order.getServicePrice());
        orderMap.put("serviceTime", order.getServiceTime());
        orderMap.put("questionDescription", order.getQuestionDescription());
        orderMap.put("notes", order.getNotes());
        orderMap.put("reserveTime", order.getReserveTime());
        orderMap.put("takeTime", order.getTakeTime());
        orderMap.put("workPreTime", order.getWorkPreTime());
        orderMap.put("workAfterTime", order.getWorkAfterTime());
        orderMap.put("paySuccessTime", order.getPaySuccessTime());
        orderMap.put("completionTime", order.getCompletionTime());
        orderMap.put("payId", order.getPayId());
        orderMap.put("commentId", order.getCommentId());
        orderMap.put("companyName", order.getCompanyName());
        orderMap.put("materialId", order.getMaterialId());
        orderMap.put("createTime", order.getCreateTime());
        orderMap.put("updateTime", order.getUpdateTime());
    }

    public String generateOrderNum() {
        long workerId = WorkerId.WORKER_ID;
        return String.valueOf(IdUtil.getSnowflake(workerId).nextId());
    }
}
